#include "js-engine.h"
#include <glib.h>
#include <glib/gstdio.h>
#include <libxml/SAX2.h>
#include <libxml/parser.h>

#define PARSER_OPTION  XML_PARSE_NOBLANKS|XML_PARSE_NOENT|XML_PARSE_NOCDATA|XML_PARSE_RECOVER
#define GADGET_GMANIFEST "gadget.gmanifest"
static GHashTable *parse_gmanifest(xmlNodePtr root);
GHashTable *load_gmanifest_xml(js_engine *engine)
{
    GString *manifestStr = NULL;
    xmlDoc *manifestDoc = NULL;
    GIOChannel *fd = NULL;
    GError *err = NULL;
    GString *entity= NULL;
    gboolean isEntity = FALSE;
    GHashTable *gmanifestTable = NULL;
    xmlNodePtr root;

    fd = g_io_channel_new_file(GADGET_GMANIFEST, "r", &err);
    if(err){
	g_error_free(err);
	return NULL;
    }
    g_io_channel_set_encoding(fd, NULL, &err);

    manifestStr = g_string_new(NULL);
    while(TRUE){
	gchar ch;
	gsize bytes_read;
	GError *err = NULL;
	GIOStatus status = 
	    g_io_channel_read_chars(fd, &ch, 1, &bytes_read, &err);
	if(err){
	    g_error_free(err);
	    g_io_channel_close(fd);
	    g_warning("gadget.gmanifest parsing error.");
	    return NULL;
	}
	if(status == G_IO_STATUS_EOF)
	    break;
	if(ch == '&') {
	    isEntity = TRUE;
	    entity = g_string_new(NULL);
	}else if(ch == ';'){
            if (isEntity == TRUE) {
		gchar *subst = NULL;
		jsval rval;
		JS_GetProperty(engine->cx, engine->glob, entity->str, &rval);
		if(JSVAL_IS_STRING(rval)){
		    subst = JS_GetStringBytes(JSVAL_TO_STRING(rval));
		}
                g_string_append(manifestStr, subst);
                isEntity = FALSE;
                g_string_free(entity, TRUE);
                entity = NULL;
            } else {
                g_string_append_c(manifestStr, ch);
            }
        } else {
            if (isEntity == FALSE) {
                g_string_append_c(manifestStr, ch);
            } else {
                g_string_append_c(entity, ch);
            }
        }
    }
    manifestDoc = xmlReadMemory(manifestStr->str, manifestStr->len,
				 NULL,NULL,0);
    g_return_val_if_fail(manifestDoc, NULL);

    root = xmlDocGetRootElement(manifestDoc);
    gmanifestTable = parse_gmanifest(root);
    xmlFreeDoc(manifestDoc);
    g_return_val_if_fail(gmanifestTable, NULL);
    return gmanifestTable;
}

static GHashTable *parse_gmanifest(xmlNodePtr root)
{
    GHashTable *table = NULL;
    xmlNode *about = root->children;
    xmlNode *ptr;
    while(about){
	if(xmlStrcasecmp(about->name, "about") == 0)
	    break;
	about = about->next;
    }
    if(about == NULL)
	return NULL;
    table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
    ptr = about->children;
    while(ptr){
	if(ptr->type == XML_ELEMENT_NODE){
	    gchar *key = g_strdup(ptr->name);
	    gchar *value = NULL;
	    if(ptr->children)
		value = g_strdup(ptr->children->content);
	    else
		value = g_strdup("");
	    g_hash_table_insert(table, key, value);
	}
	ptr = ptr->next;
    }
    return table;
}
